<template>
  <uvPopup class="cascader-popup" v-model="show" close round :title="title" v-bind="popupProps">
    <div class="uv-cascader">
      <uvTab
        v-if="show"
        color="#969799"
        :acitve-index="acitveIndex"
        @change="tabChange"
        :list="tabList"
        :placeholder="placeholder"
        scroll
        shrink
        v-bind="tabProps"
      />
      <div class="uv-cascader-content" ref="contentRef">
        <swiper @change="swiperChange" class="uv-cascader-content-list" :current="acitveIndex">
          <swiper-item v-for="(item, index) in tabs" :key="index">
            <scroll-view scroll-y style="height: 100%">
              <div class="uv-cascader-content-item-warp">
                <div
                  @click="tabItemClick(chil, idx)"
                  class="uv-cascader-content-item"
                  v-for="(chil, idx) in item.options"
                  :class="
                    chil[valueKey] === item.selected?.[valueKey]
                      ? 'uv-cascader-content-active-item'
                      : ''
                  "
                  :key="idx"
                >
                  <div>{{ chil[labelKey] }}</div>

                  <!-- <image class="select-icon-class" v-if="chil[valueKey]===item.selected?.[valueKey]" :src="selectIcon" /> -->
                </div>
              </div>
            </scroll-view>
          </swiper-item>
        </swiper>
      </div>
    </div>
  </uvPopup>
</template>

<script setup>
import { ref, nextTick, computed, watch, getCurrentInstance } from 'vue'
import uvPopup from './popup'
import uvTab from './tab'

const instance = getCurrentInstance()

const props = defineProps({
  popupProps: {
    type: Object,
    default: () => ({}),
  },
  tabProps: {
    type: Object,
    default: () => ({}),
  },
  modelValue: {
    type: [String, Number],
    default: '',
  },
  list: {
    type: Array,
    default: () => [],
  },
  labelKey: {
    type: String,
    default: 'label',
  },
  valueKey: {
    type: String,
    default: 'value',
  },
  childrenKey: {
    type: String,
    default: 'children',
  },
  title: {
    type: String,
    default: '',
  },
  placeholder: {
    type: String,
    default: '请选择',
  },
})

const emit = defineEmits(['finish', 'change', 'close', 'update:modelValue'])

const show = ref(false)

const open = () => {
  show.value = true
}

const close = () => {
  show.value = false
  emit('close')
}

const acitveIndex = ref(0)

const swiperChange = (e) => {
  acitveIndex.value = e.detail.current
}

const tabs = ref([])

const contentRef = ref(null)
const itemDomList = ref(null)
const pageWidth = ref(0)

watch([() => show.value, () => tabs.value.length], () => {
  if (show.value) {
    nextTick(() => {
      const dom = uni.createSelectorQuery().in(instance)
      dom
        .select('.uv-cascader-content')
        .boundingClientRect((data) => {
          pageWidth.value = data.width
        })
        .exec()
      itemDomList.value = dom.selectAll('.uv-cascader-content-item-warp')
    })
  }
})

const tabItemClick = async (item, idx) => {
  emit('update:modelValue', item[props.valueKey])
  if (idx + 1 < tabs.value.length) {
    acitveIndex.value = idx + Math.random()
    await nextTick()
    acitveIndex.value = idx + 1
  }
  emit('change', item[props.valueKey])
  updateTabs()
  if (!item[props.childrenKey] || item[props.childrenKey].length < 1) {
    const value = []
    const label = []
    tabs.value.forEach((it) => {
      if (it.selected) {
        value.push(it.selected[props.valueKey])
        label.push(it.selected[props.labelKey])
      }
    })
    emit('finish', {
      value: value.join('/'),
      label: label.join('/'),
    })
    close()
  }
}

const tabList = computed(() => {
  const { labelKey, placeholder } = props
  const arr = []
  tabs.value.forEach((item) => {
    const { selected } = item
    const title = selected ? selected[labelKey] : placeholder
    arr.push(title)
  })
  return arr
})

const tabChange = async (idx) => {
  acitveIndex.value = idx + Math.random()
  await nextTick()
  acitveIndex.value = idx
}

const getSelectedOptionsByValue = (options, value) => {
  const { valueKey, childrenKey } = props
  for (const option of options) {
    if (option[valueKey] === value) {
      return [option]
    }

    if (option[childrenKey]) {
      const selectedOptions = getSelectedOptionsByValue(option[childrenKey], value)
      if (selectedOptions) {
        return [option, ...selectedOptions]
      }
    }
  }
}
const updateTabs = () => {
  const { list, valueKey, childrenKey, modelValue } = props

  if (modelValue !== undefined) {
    const selectedOptions = getSelectedOptionsByValue(list, modelValue)

    if (selectedOptions) {
      let optionsCursor = list

      tabs.value = selectedOptions.map((option) => {
        const tab = {
          options: optionsCursor,
          selected: option,
        }

        const next = optionsCursor.find((item) => item[valueKey] === option[valueKey])
        if (next) {
          optionsCursor = next[childrenKey]
        }

        return tab
      })

      if (optionsCursor && optionsCursor.length > 0) {
        tabs.value.push({
          options: optionsCursor,
          selected: null,
        })
      }

      nextTick(() => {
        acitveIndex.value = tabList.value.length - 1
      })
      return
    }
  }

  tabs.value = [
    {
      options: list,
      selected: null,
    },
  ]
}
updateTabs()

watch(() => props.list, updateTabs, { deep: true })

watch(
  () => props.modelValue,
  (value) => {
    if (value !== undefined) {
      const values = tabs.value.map((tab) => tab.selected?.[props.valueKey])
      if (values.includes(value)) {
        return
      }
    }
    updateTabs()
  },
)

const selectIcon =
  ''

defineExpose({
  open,
  close,
})
</script>

<style lang="scss" scoped>
.uv-cascader {
  display: flex;
  width: 100%;
  height: 70vh;
  flex-direction: column;
  .uv-cascader-content {
    overflow: hidden;
    padding: 10px 0;
    width: 100%;
    min-height: 0;
    flex: 1 0;
    .uv-cascader-content-list {
      height: 100%;
      .uv-cascader-content-item-warp {
        position: relative;
        display: flex;
        width: 100%;
        flex-direction: column;
        .uv-cascader-content-item {
          display: flex;
          justify-content: space-between;
          align-items: center;
          padding: 10px 16px;
          width: 100%;
          font-size: 14px;
          color: #323233;
          &:active {
            background-color: #f2f3f5;
          }
        }
        .uv-cascader-content-active-item {
          font-weight: 700;
          color: #54B9CC;
        }
      }
    }
  }
}
.select-icon-class {
  width: 20px;
  height: 20px;
  filter: drop-shadow(#54B9CC 0 0);
}
</style>
